home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickTime™ VR 2.0 SDK / QTVR C⁄C++ Runtime API / Sample Code / VRShell Sample Code / VR3DObjects / TestFunctions.c < prev    next >
Encoding:
Text File  |  1997-05-22  |  38.7 KB  |  1,366 lines  |  [TEXT/MPCC]

  1. //
  2. //    File:        TestFunctions.c
  3. //
  4. //    Contains:    QuickDraw 3D support for QuickTime VR movies.
  5. //
  6. //    Written by:    Tim Monroe
  7. //                parts modeled on BoxMoov code by Nick Thompson, Rick Evans, and Robert Dierkes
  8. //                and on code in QD3D book (by yours truly!)
  9. //
  10. //    Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <14>         01/24/97    rtm        slight adjustment to camera-setting algorithm
  15. //       <13>         01/23/97    rtm        reworked camera-setting algorithm; now it works fine!
  16. //                                    (replaced VR3DObjects_RotateCamera[XY] with VR3DObjects_SetCamera)
  17. //       <12>         01/20/97    rtm        various small tweaks; nothing major 
  18. //       <11>         01/17/97    rtm        further work on tilting; still unable to fix it entirely 
  19. //       <10>         01/16/97    rtm        added VR3DObjects_SetCameraAspectRatio 
  20. //                                    and VR3DObjects_UpdateDrawContext to handle window resizing
  21. //       <9>         01/14/97    rtm        added polyhedron object to VR3DObjects_CreateModel
  22. //                                    added static texture support
  23. //       <8>         01/13/97    rtm        added some object types to VR3DObjects_CreateModel
  24. //       <7>         01/10/97    rtm        added VR3DObjects_MCActionFilterProc
  25. //                                    (later merged into ApplicationMCActionFilterProc)
  26. //       <6>         01/09/97    rtm        fixed jittering on pan/tilt/zoom;
  27. //                                    fixed VR3DObjects_RotateCameraX for correct tilting
  28. //       <5>         01/03/97    rtm        added animation (that is, rotation) support for 3D objects
  29. //       <4>         12/23/96    rtm        further work on 3D overlay; fixed some jitters
  30. //       <3>         12/20/96    rtm        added zooming support;
  31. //                                    implemented 3D overlay instead of 3D test window
  32. //       <2>         12/16/96    rtm        added 3D test window, intercept procedure
  33. //                                    added QuickTime movie texture mapping support
  34. //       <1>         12/13/96    rtm        first file
  35. //       
  36. //
  37. // This file provides functions to display 3D objects at specific locations in a panorama.
  38. //
  39. // Our strategy: QuickDraw 3D is a "slave" to VR: whenever the VR environment changes,
  40. // we change the QuickDraw 3D camera accordingly and render a new image to our view.
  41. // All this occurs in the prescreen buffer imaging complete procedure.
  42. //
  43. //
  44. // TODO:
  45. // + stop a window's movie sound immediately when a suspend or deactivate event is received (?)
  46. // + add volume control button to affect QT movie sound track (already coded, but needs testing on new build)
  47. // + add support for VR object nodes (?)
  48.  
  49.  
  50. // header files
  51. #include "TestFunctions.h"
  52.  
  53. #include "MacFramework.h"
  54. #include "QTVRUtilities.h"
  55.  
  56.  
  57. // system headers
  58. #include <Windows.h>
  59. #include <Resources.h>
  60. #include <TextUtils.h>
  61. #include <fp.h>
  62.  
  63.  
  64. // global variables
  65. extern Boolean            gHasQuickDraw3D;                    // is QuickDraw 3D available?
  66.  
  67.  
  68. // constants
  69. const RGBColor            kClearColor = {0x0000, 0xffff, 0x0000};
  70. const RGBColor            kWhiteColor = {0xffff, 0xffff, 0xffff};
  71.  
  72.  
  73. //////////
  74. //
  75. // VR3DObjects_Init
  76. // Initialize for QuickDraw 3D.
  77. //
  78. //////////
  79.  
  80. void VR3DObjects_Init (void)
  81. {
  82.     TQ3Status            myStatus;
  83.  
  84.     // make sure that QuickDraw 3D is available;
  85.     if (VR3DObjects_IsQD3DAvailable()) {
  86.         gHasQuickDraw3D = true;
  87.     } else {
  88.         gHasQuickDraw3D = false;
  89.         ShowWarning("\pQuickDraw 3D is not available in the current environment: ", 0);
  90.     }
  91.     
  92.     // now perform any initialization
  93.     if (gHasQuickDraw3D) {
  94.         myStatus = Q3Initialize();
  95.         if (myStatus != kQ3Success) {
  96.             ShowWarning("\pCould not initialize QuickDraw 3D: ", 0);
  97.         }
  98.     }
  99. }
  100.  
  101.  
  102. //////////
  103. //
  104. // VR3DObjects_Stop
  105. // Clean up for QuickDraw 3D.
  106. //
  107. //////////
  108.  
  109. void VR3DObjects_Stop (void)
  110. {
  111.     TQ3Status            myStatus;
  112.     
  113.     // perform any QD3D-related shutdown operations
  114.     if (gHasQuickDraw3D) {
  115.         myStatus = Q3Exit();
  116.         if (myStatus != kQ3Success) {
  117.             // ShowWarning("\pCould not exit QuickDraw 3D: ", 0);
  118.         }
  119.     }
  120. }
  121.  
  122.  
  123. //////////
  124. //
  125. // VR3DObjects_IsQD3DAvailable
  126. // Is QuickDraw 3D available in the present operating environment?
  127. //
  128. //////////
  129.  
  130. Boolean VR3DObjects_IsQD3DAvailable (void)
  131. {
  132.     return((Boolean)Q3Initialize != kUnresolvedSymbolAddress);
  133. }
  134.  
  135.  
  136. //////////
  137. //
  138. // VR3DObjects_InitWindowData
  139. // Initialize the window-specific 3D data.
  140. //
  141. //////////
  142.  
  143. ApplicationDataHdl VR3DObjects_InitWindowData (WindowObject theWindowObject)
  144. {
  145.     ApplicationDataHdl    myAppData;
  146.     TQ3Point3D            myOrigin = {0.0, 0.0, -k3DObjectDistance};
  147.     OSErr                myErr;
  148.     Rect                myRect;
  149.     CGrafPtr            mySavedPort;
  150.     GDHandle            mySavedDevice;
  151.     
  152.     myAppData = (ApplicationDataHdl)NewHandleClear(sizeof(ApplicationDataRecord));
  153.     if (myAppData != NULL) {
  154.     
  155.         // get the current drawing environment
  156.         GetGWorld(&mySavedPort, &mySavedDevice);
  157.  
  158.         // lock the application data handle
  159.         HLock((Handle)myAppData);
  160.         
  161.         // initialize the data fields to reasonable values
  162.         (**myAppData).fWindow = (**theWindowObject).fWindow;
  163.         
  164.         // get the size of the destination window
  165.         if ((**theWindowObject).fMovie != NULL) {
  166.             GetMovieBox((**theWindowObject).fMovie, &myRect);
  167.         }
  168.                 
  169.         // create an offscreen GWorld that is the size of the window area
  170.         // (this GWorld is our draw context buffer)
  171.         myErr = NewGWorld(&(**myAppData).fGWorld, 32, &myRect, NULL, NULL, 0L);
  172.         if (myErr != noErr)
  173.             return(NULL);
  174.  
  175.         // erase the draw context buffer to our masking color
  176.         SetGWorld((**myAppData).fGWorld, NULL);
  177.         RGBBackColor(&kClearColor);
  178.         EraseRect(&myRect);
  179.                 
  180.         // restore the original drawing environment
  181.         SetGWorld(mySavedPort, mySavedDevice);
  182.                                 
  183.         // create a new view attached to the offscreen GWorld
  184.         (**myAppData).fView = VR3DObjects_CreateView((**myAppData).fGWorld);
  185.         
  186.         // create the model (the default model is a box)
  187.         (**myAppData).fModel = VR3DObjects_CreateModel(kQ3GeometryTypeBox);
  188.         (**myAppData).fObjectIndex = iBox;
  189.     
  190.         // set the drawing styles
  191.         (**myAppData).fInterpolation = Q3InterpolationStyle_New(kQ3InterpolationStyleVertex);
  192.         (**myAppData).fBackFacing = Q3BackfacingStyle_New(kQ3BackfacingStyleBoth);
  193.         (**myAppData).fFillStyle = Q3FillStyle_New(kQ3FillStyleFilled);
  194.  
  195.         // set the rotation matrix to the identity matrix
  196.         Q3Matrix4x4_SetIdentity(&(**myAppData).fRotation);
  197.         
  198.         // initialize other fields of application data structure
  199.         (**myAppData).fGroupScale = 1.0;            // set the group scale and center        
  200.         (**myAppData).fGroupCenter = myOrigin;    
  201.         (**myAppData).fTexture = NULL;                // set the texture to NULL
  202.         (**myAppData).fTextureIsMovie = false;        // set the texture-is-movie flag to OFF
  203.         (**myAppData).fObjectIsAnimated = false;    // set the object animation flag to OFF
  204.         (**myAppData).fCameraChanged = true;        // set the camera-changed flag to ON
  205.         (**myAppData).fMustRender = true;            // set the render flag to ON
  206.         (**myAppData).fQTMovieHasSound = false;        // set the sound track flag to OFF
  207.         (**myAppData).fQD3DFOVIsVert = true;        // set the FOV vertical orientation flag to ON
  208.  
  209.         // unlock the handle
  210.         HUnlock((Handle)myAppData);
  211.     }
  212.     
  213.     return(myAppData);
  214. }
  215.  
  216.  
  217. //////////
  218. //
  219. // VR3DObjects_CreateModel
  220. // Return a display group object containing the QD3D object(s) in our model.
  221. //
  222. //////////
  223.  
  224. TQ3GroupObject VR3DObjects_CreateModel (TQ3ObjectType theObjectType)
  225. {
  226.     TQ3GroupObject            myGroup = NULL;
  227.     TQ3GeometryObject        myObject;
  228.     TQ3ShaderObject            myIlluminationShader;
  229.     TQ3ColorRGB                myColor;
  230.     
  231.     // create a new display group
  232.     myGroup = Q3DisplayGroup_New();
  233.     if (myGroup != NULL ) {
  234.         
  235.         // create an illumination shader and add it to our display group    
  236.         myIlluminationShader = Q3PhongIllumination_New();
  237.         Q3Group_AddObject(myGroup, myIlluminationShader);
  238.         
  239.         // set the color of the 3D object
  240.         Q3ColorRGB_Set(&myColor, 1.0, 1.0, 1.0);
  241.         
  242.         // create the specified type of 3D object
  243.         switch (theObjectType) {
  244.             case kQ3GeometryTypeBox: {                // create a box
  245.                 TQ3BoxData                myBoxData;
  246.                 
  247.                 myBoxData.boxAttributeSet = Q3AttributeSet_New();
  248.                 Q3AttributeSet_Add(myBoxData.boxAttributeSet, kQ3AttributeTypeDiffuseColor, &myColor);
  249.                 myBoxData.faceAttributeSet = NULL;
  250.                 Q3Point3D_Set(&myBoxData.origin, -0.5, -0.5, -0.5);
  251.                 Q3Vector3D_Set(&myBoxData.orientation, 0, 1, 0);
  252.                 Q3Vector3D_Set(&myBoxData.majorAxis, 0, 0, 1);    
  253.                 Q3Vector3D_Set(&myBoxData.minorAxis, 1, 0, 0);    
  254.                 myObject = Q3Box_New(&myBoxData);
  255.                 break;
  256.             }
  257.                 
  258.             case kQ3GeometryTypeEllipsoid: {        // create an ellipsoid
  259.                 TQ3EllipsoidData        myEllipsoidData;
  260.                 
  261.                 myEllipsoidData.ellipsoidAttributeSet = Q3AttributeSet_New();
  262.                 Q3AttributeSet_Add(myEllipsoidData.ellipsoidAttributeSet, kQ3AttributeTypeDiffuseColor, &myColor);
  263.                 myEllipsoidData.interiorAttributeSet = NULL;
  264.                 myEllipsoidData.caps = NULL;
  265.                 Q3Point3D_Set(&myEllipsoidData.origin, 0.0, 0.0, 0.0);
  266.                 Q3Vector3D_Set(&myEllipsoidData.orientation, 0, 1, 0);
  267.                 Q3Vector3D_Set(&myEllipsoidData.majorRadius, 0, 0, 1);    
  268.                 Q3Vector3D_Set(&myEllipsoidData.minorRadius, 1, 0, 0);    
  269.                 myObject = Q3Ellipsoid_New(&myEllipsoidData);
  270.                 
  271.                 // set a finer subdivision style
  272.                 VR3DObjects_SetSubdivisionStyle(myGroup, 20);
  273.                 break;
  274.             }
  275.             
  276.             case kQ3GeometryTypeCylinder: {            // create a cylinder
  277.                 TQ3CylinderData            myCylinderData;
  278.                 
  279.                 myCylinderData.cylinderAttributeSet = Q3AttributeSet_New();
  280.                 Q3AttributeSet_Add(myCylinderData.cylinderAttributeSet, kQ3AttributeTypeDiffuseColor, &myColor);
  281.                 myCylinderData.interiorAttributeSet = NULL;
  282.                 myCylinderData.topAttributeSet = NULL;
  283.                 myCylinderData.faceAttributeSet = NULL;
  284.                 myCylinderData.bottomAttributeSet = NULL;
  285.                 myCylinderData.caps = kQ3EndCapMaskTop | kQ3EndCapMaskBottom;
  286.                 Q3Point3D_Set(&myCylinderData.origin, 0.0, -0.5, 0.0);
  287.                 Q3Vector3D_Set(&myCylinderData.orientation, 0, 1, 0);
  288.                 Q3Vector3D_Set(&myCylinderData.majorRadius, 0, 0, 0.5);    
  289.                 Q3Vector3D_Set(&myCylinderData.minorRadius, 0.5, 0, 0);    
  290.                 myObject = Q3Cylinder_New(&myCylinderData);
  291.                 
  292.                 // set a finer subdivision style
  293.                 VR3DObjects_SetSubdivisionStyle(myGroup, 20);
  294.                 break;
  295.             }
  296.             
  297.             case kQ3GeometryTypeCone: {                // create a cone
  298.                 TQ3ConeData                myConeData;
  299.                 
  300.                 myConeData.coneAttributeSet = Q3AttributeSet_New();
  301.                 Q3AttributeSet_Add(myConeData.coneAttributeSet, kQ3AttributeTypeDiffuseColor, &myColor);
  302.                 myConeData.interiorAttributeSet = NULL;
  303.                 myConeData.faceAttributeSet = NULL;
  304.                 myConeData.bottomAttributeSet = NULL;
  305.                 myConeData.caps = kQ3EndCapMaskBottom;
  306.                 Q3Point3D_Set(&myConeData.origin, 0.0, -0.5, 0.0);
  307.                 Q3Vector3D_Set(&myConeData.orientation, 0, 1, 0);
  308.                 Q3Vector3D_Set(&myConeData.majorRadius, 0, 0, 0.5);    
  309.                 Q3Vector3D_Set(&myConeData.minorRadius, 0.5, 0, 0);    
  310.                 myObject = Q3Cone_New(&myConeData);
  311.                 break;
  312.             }
  313.             
  314.             case kQ3GeometryTypeTorus: {            // create a torus
  315.                 TQ3TorusData                myTorusData;
  316.                 
  317.                 myTorusData.torusAttributeSet = Q3AttributeSet_New();
  318.                 Q3AttributeSet_Add(myTorusData.torusAttributeSet, kQ3AttributeTypeDiffuseColor, &myColor);
  319.                 myTorusData.interiorAttributeSet = NULL;
  320.                 myTorusData.caps = NULL;
  321.                 myTorusData.ratio = 1.0;
  322.                 Q3Point3D_Set(&myTorusData.origin, 0.0, 0.0, 0.0);
  323.                 Q3Vector3D_Set(&myTorusData.orientation, 0, 0.3, 0);
  324.                 Q3Vector3D_Set(&myTorusData.majorRadius, 0, 0, 0.5);    
  325.                 Q3Vector3D_Set(&myTorusData.minorRadius, 0.5, 0, 0);    
  326.                 myObject = Q3Torus_New(&myTorusData);
  327.                 
  328.                 // set a finer subdivision style
  329.                 VR3DObjects_SetSubdivisionStyle(myGroup, 20);
  330.                 break;
  331.             }
  332.             
  333.             case kQ3GeometryTypePolyhedron: {        // create a polyhedron
  334.                 TQ3PolyhedronData            myPolyData;
  335.                 static TQ3Vertex3D            myVertices[4] = {
  336.                                                 { {-1.0, -1.0, 0.0}, NULL},
  337.                                                 { {+1.0, -1.0, 0.0}, NULL},
  338.                                                 { {+1.0, +1.0, 0.0}, NULL},
  339.                                                 { {-1.0, +1.0, 0.0}, NULL}
  340.                                             };
  341.                 
  342.                 static TQ3Param2D            myUVParams[4] = {
  343.                                                 {0.0, 0.0},
  344.                                                 {1.0, 0.0},
  345.                                                 {1.0, 1.0},
  346.                                                 {0.0, 1.0}
  347.                                             };
  348.                 
  349.                 TQ3PolyhedronTriangleData    myTriangles[2] = {
  350.                                                 { { 0, 1, 3 }, kQ3PolyhedronEdge01 | kQ3PolyhedronEdge20, NULL },
  351.                                                 { { 1, 2, 3 }, kQ3PolyhedronEdge01 | kQ3PolyhedronEdge12, NULL }
  352.                                             };
  353.  
  354.                 short                        myIndex;
  355.     
  356.                 // set up vertices, edges, and triangular faces
  357.                 myPolyData.numVertices = 4;
  358.                 myPolyData.vertices = myVertices;    
  359.                 myPolyData.numEdges = 0;
  360.                 myPolyData.edges = NULL;
  361.                 myPolyData.numTriangles    = 2;
  362.                 myPolyData.triangles = myTriangles;
  363.                 
  364.                 // add uv parameterization to the polyhedron
  365.                 for (myIndex = 0; myIndex < myPolyData.numVertices; myIndex++) {                    
  366.                     myVertices[myIndex].attributeSet = Q3AttributeSet_New();
  367.                     Q3AttributeSet_Add(myVertices[myIndex].attributeSet, kQ3AttributeTypeSurfaceUV, &myUVParams[myIndex]);
  368.                 }
  369.                 
  370.                 myPolyData.polyhedronAttributeSet = Q3AttributeSet_New();
  371.                 Q3AttributeSet_Add(myPolyData.polyhedronAttributeSet, kQ3AttributeTypeDiffuseColor, &myColor);
  372.  
  373.                 myObject = Q3Polyhedron_New(&myPolyData);
  374.                 break;
  375.             }
  376.             
  377.             default:
  378.                 break;
  379.         }
  380.         
  381.         // add the object to the group
  382.         Q3Group_AddObject(myGroup, myObject);
  383.     }
  384.     
  385.     // dispose of the objects we created here
  386.     // (we can do this, because they've been added to the group)
  387.     if (myIlluminationShader) 
  388.         Q3Object_Dispose(myIlluminationShader);    
  389.                 
  390.     if (myObject) 
  391.         Q3Object_Dispose(myObject);
  392.     
  393.     return(myGroup);
  394. }
  395.  
  396.  
  397. //////////
  398. //
  399. // VR3DObjects_CreateView
  400. // Return a view object for the QD3D objects in our model.
  401. //
  402. //////////
  403.  
  404. TQ3ViewObject VR3DObjects_CreateView (GWorldPtr theGWorld)
  405. {
  406.     TQ3Status                myStatus;
  407.     TQ3ViewObject            myView;
  408.     TQ3DrawContextObject    myDrawContext;
  409.     TQ3RendererObject        myRenderer;
  410.     TQ3CameraObject            myCamera;
  411.     TQ3GroupObject            myLights;
  412.     
  413.     // create a new view object
  414.     myView = Q3View_New();
  415.     if (myView == NULL)
  416.         goto bail;
  417.     
  418.     // create and set draw context
  419.     myDrawContext = VR3DObjects_CreateDrawContext(theGWorld);
  420.     if (myDrawContext == NULL)
  421.         goto bail;
  422.         
  423.     myStatus = Q3View_SetDrawContext(myView, myDrawContext);
  424.     if (myStatus == kQ3Failure)
  425.         goto bail;
  426.  
  427.     Q3Object_Dispose(myDrawContext);
  428.     
  429.     // create and set renderer
  430.     myRenderer = Q3Renderer_NewFromType(kQ3RendererTypeInteractive);
  431.     if (myRenderer == NULL) 
  432.         goto bail;
  433.     
  434.     myStatus = Q3View_SetRenderer(myView, myRenderer);
  435.     if (myStatus == kQ3Failure)
  436.         goto bail;
  437.  
  438.     Q3Object_Dispose(myRenderer);
  439.     
  440.     // create and set camera
  441.     myCamera = VR3DObjects_CreateCamera(theGWorld);
  442.     if (myCamera == NULL)
  443.         goto bail;
  444.         
  445.     myStatus = Q3View_SetCamera(myView, myCamera);
  446.     if (myStatus == kQ3Failure)
  447.         goto bail;
  448.  
  449.     Q3Object_Dispose(myCamera) ;
  450.     
  451.     // create and set lights
  452.     myLights = VR3DObjects_CreateLights();
  453.     if (myLights == NULL)
  454.         goto bail;
  455.         
  456.     myStatus = Q3View_SetLightGroup(myView, myLights);
  457.     if (myStatus == kQ3Failure)
  458.         goto bail;
  459.  
  460.     Q3Object_Dispose(myLights);
  461.  
  462.     return(myView);
  463.     
  464. bail:
  465.     // if any of the above creations failed, don't return a view
  466.     return(NULL);
  467. }
  468.  
  469.  
  470. //////////
  471. //
  472. // VR3DObjects_CreateLights
  473. // Return a light group object for the QD3D objects in our model.
  474. // For displaying embedded movies, we just need the ambient light.
  475. //
  476. //////////
  477.  
  478. TQ3GroupObject VR3DObjects_CreateLights (void)
  479. {
  480.     TQ3GroupPosition            myGroupPosition;
  481.     TQ3GroupObject                myLightList;
  482.     TQ3LightData                myLightData;
  483.     TQ3PointLightData            myPointLightData;
  484.     TQ3DirectionalLightData        myDirectionalLightData;
  485.     TQ3LightObject                myAmbientLight, myPointLight, myFillLight;
  486.     TQ3Point3D                    myPointLocation =    {-10.0, 0.0, 10.0};
  487.     TQ3Vector3D                    myFillDirection =    {10.0, 0.0, 10.0};
  488.     TQ3ColorRGB                    myWhiteLight =        {1.0, 1.0, 1.0};
  489.     
  490.     // set up light data for ambient light
  491.     myLightData.isOn = kQ3True;
  492.     myLightData.color = myWhiteLight;
  493.     
  494.     // create the ambient light
  495.     myLightData.brightness = 1.0;
  496.     myAmbientLight = Q3AmbientLight_New(&myLightData);
  497.     if (myAmbientLight == NULL)
  498.         goto bail;
  499.     
  500.     // create a point light
  501.     myLightData.brightness = 1.0;
  502.     myPointLightData.lightData = myLightData;
  503.     myPointLightData.castsShadows = kQ3False;
  504.     myPointLightData.attenuation = kQ3AttenuationTypeNone;
  505.     myPointLightData.location = myPointLocation;
  506.     myPointLight = Q3PointLight_New(&myPointLightData);
  507.     if (myPointLight == NULL)
  508.         goto bail;
  509.  
  510.     // create a directional light for fill
  511.     myLightData.brightness = 0.2;
  512.     myDirectionalLightData.lightData = myLightData;
  513.     myDirectionalLightData.castsShadows = kQ3False;
  514.     myDirectionalLightData.direction = myFillDirection;
  515.     myFillLight = Q3DirectionalLight_New(&myDirectionalLightData);
  516.     if (myFillLight == NULL)
  517.         goto bail;
  518.  
  519.     // create a light group and add each of the lights to the group
  520.     myLightList = Q3LightGroup_New();
  521.     if (myLightList == NULL)
  522.         goto bail;
  523.     myGroupPosition = Q3Group_AddObject(myLightList, myAmbientLight);
  524.     if (myGroupPosition == 0)
  525.         goto bail;
  526.     //myGroupPosition = Q3Group_AddObject(myLightList, myPointLight);
  527.     //if (myGroupPosition == 0)
  528.     //    goto bail;
  529.     //myGroupPosition = Q3Group_AddObject(myLightList, myFillLight);
  530.     //if (myGroupPosition == 0)
  531.     //    goto bail;
  532.  
  533.     Q3Object_Dispose(myAmbientLight);
  534.     Q3Object_Dispose(myPointLight);
  535.     Q3Object_Dispose(myFillLight);
  536.  
  537.     return(myLightList);
  538.     
  539. bail:
  540.     // if any of the above creations failed, don't return a light group
  541.     return(NULL);
  542. }
  543.  
  544.  
  545. //////////
  546. //
  547. // VR3DObjects_CreateDrawContext
  548. // Return a draw context object for the QD3D objects in our model.
  549. //
  550. //////////
  551.  
  552. TQ3DrawContextObject VR3DObjects_CreateDrawContext (GWorldPtr theGWorld)
  553. {
  554.     TQ3DrawContextObject        myDrawContext;
  555.     TQ3PixmapDrawContextData    myPixMapDrawContextData;
  556.     TQ3DrawContextData            myDrawContextData;
  557.     PixMapHandle                 myPixMap;
  558.     Rect                        myRect;
  559.     TQ3ColorARGB                myClearColor = {1.0, 0.0, 0.0, 0.0};
  560.     float                        myFactor = 0xffff;
  561.     
  562.     // set the background color;
  563.     // note that RGBColor is defined in the range 0-65535,
  564.     // while TQ3ColorARGB is defined in the range 0.0-1.0; hence the division....
  565.     myClearColor.a = 0.0;
  566.     myClearColor.r = kClearColor.red / myFactor;
  567.     myClearColor.g = kClearColor.green / myFactor;
  568.     myClearColor.b = kClearColor.blue / myFactor;
  569.     
  570.     // fill in draw context data
  571.     myDrawContextData.clearImageMethod = kQ3ClearMethodWithColor;
  572.     myDrawContextData.clearImageColor = myClearColor;
  573.     myDrawContextData.paneState = kQ3False;
  574.     myDrawContextData.maskState = kQ3False;
  575.     myDrawContextData.doubleBufferState = kQ3False;
  576.  
  577.     myPixMapDrawContextData.drawContextData = myDrawContextData;
  578.     
  579.     myPixMap = GetGWorldPixMap(theGWorld);
  580.     LockPixels(myPixMap);
  581.  
  582.     myRect = theGWorld->portRect;
  583.  
  584.     myPixMapDrawContextData.pixmap.width = myRect.right - myRect.left;
  585.     myPixMapDrawContextData.pixmap.height = myRect.bottom - myRect.top;
  586.     
  587.     myPixMapDrawContextData.pixmap.rowBytes = (**myPixMap).rowBytes & 0x7FFF;
  588.     myPixMapDrawContextData.pixmap.pixelType = kQ3PixelTypeRGB32;
  589.     myPixMapDrawContextData.pixmap.pixelSize = 32;
  590.  
  591.     myPixMapDrawContextData.pixmap.bitOrder = kQ3EndianBig;
  592.     myPixMapDrawContextData.pixmap.byteOrder = kQ3EndianBig;
  593.     
  594.     myPixMapDrawContextData.pixmap.image = GetPixBaseAddr(myPixMap);
  595.     
  596.     // create draw context and return it
  597.     myDrawContext = Q3PixmapDrawContext_New(&myPixMapDrawContextData);
  598.  
  599.     return(myDrawContext);
  600. }
  601.  
  602.  
  603. //////////
  604. //
  605. // VR3DObjects_CreateCamera
  606. // Return a camera object for the QD3D objects in our model.
  607. // Note that some of the initial values are wrong and will soon be reset (in InitApplicationWindowObject).
  608. //
  609. //////////
  610.  
  611. TQ3CameraObject VR3DObjects_CreateCamera (CGrafPtr thePort)
  612. {
  613.     TQ3CameraObject                    myCamera;
  614.     TQ3ViewAngleAspectCameraData    myCameraData;
  615.     
  616.     TQ3Point3D                         myFrom         = {0.0, 0.0, 0.0};
  617.     TQ3Point3D                         myTo         = {0.0, 0.0, -6.0};    // we're looking down negative z axis
  618.     TQ3Vector3D                     myUp         = {0.0, 1.0, 0.0};
  619.  
  620.     float                             myFOV        = 1.00;                // initial FOV really depends on QTVR instance, so we reset this in InitApplicationWindowObject
  621.     float                             myHither    = 0.001;
  622.     float                             myYon         = 100.0;
  623.     
  624.     myCameraData.cameraData.placement.cameraLocation = myFrom;
  625.     myCameraData.cameraData.placement.pointOfInterest = myTo;
  626.     myCameraData.cameraData.placement.upVector = myUp;
  627.  
  628.     myCameraData.cameraData.range.hither = myHither;
  629.     myCameraData.cameraData.range.yon = myYon;
  630.  
  631.     // the default camera view port
  632.     myCameraData.cameraData.viewPort.origin.x = -1.0;
  633.     myCameraData.cameraData.viewPort.origin.y = 1.0;
  634.     myCameraData.cameraData.viewPort.width = 2.0;
  635.     myCameraData.cameraData.viewPort.height = 2.0;
  636.     
  637.     // some default FOV and aspect ratio values
  638.     myCameraData.fov = myFOV;
  639.     myCameraData.aspectRatioXToY =
  640.         (float) (thePort->portRect.right - thePort->portRect.left) / 
  641.         (float) (thePort->portRect.bottom - thePort->portRect.top);
  642.         
  643.     myCamera = Q3ViewAngleAspectCamera_New(&myCameraData);
  644.  
  645.     return(myCamera);
  646. }
  647.  
  648.  
  649. //////////
  650. //
  651. // VR3DObjects_SetSubdivisionStyle
  652. // Create a subdivision style and add it to the specified group.
  653. //
  654. //////////
  655.  
  656. void VR3DObjects_SetSubdivisionStyle (TQ3GroupObject theGroup, short theNumDivisions)
  657. {
  658.     TQ3SubdivisionStyleData        myStyleData;
  659.     TQ3StyleObject                myStyleObject;
  660.     
  661.     // set a subdivision style
  662.     myStyleData.method = kQ3SubdivisionMethodConstant;
  663.     myStyleData.c1 = theNumDivisions;
  664.     myStyleData.c2 = theNumDivisions;
  665.     myStyleObject = Q3SubdivisionStyle_New(&myStyleData);
  666.     Q3Group_AddObject(theGroup, myStyleObject);
  667.     Q3Object_Dispose(myStyleObject);
  668. }
  669.  
  670.  
  671. //////////
  672. //
  673. // VR3DObjects_AnimateModel
  674. // Animate the QuickDraw 3D model.
  675. //
  676. //////////
  677.  
  678. void VR3DObjects_AnimateModel (WindowObject theWindowObject)
  679. {
  680.     TQ3Matrix4x4        myMatrix;
  681.     ApplicationDataHdl    myAppData;
  682.     TQ3Vector3D            myVector;
  683.     
  684.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  685.     if (myAppData == NULL)
  686.         return;
  687.         
  688.     // rotate the object around the global z and local y axes
  689.     Q3Matrix4x4_SetRotate_Z(&myMatrix, -kAnimateRadians);
  690.     Q3Matrix4x4_Multiply(&(**myAppData).fRotation, &myMatrix, &(**myAppData).fRotation);
  691.     
  692.     Q3Vector3D_Set(&myVector, 0.0, 1.0, 0.0);
  693.     Q3Matrix4x4_SetRotateAboutAxis(&myMatrix, &(**myAppData).fGroupCenter, &myVector, kAnimateRadians);
  694.     Q3Matrix4x4_Multiply(&(**myAppData).fRotation, &myMatrix, &(**myAppData).fRotation);
  695. }
  696.  
  697.  
  698. //////////
  699. //
  700. // VR3DObjects_DrawModel
  701. // Draw the QuickDraw 3D model into the (offscreen GWorld) pixmap draw context.
  702. // This routine is called only in the prescreen buffer imaging complete procedure.
  703. //
  704. //////////
  705.  
  706. TQ3Status VR3DObjects_DrawModel (WindowObject theWindowObject)
  707. {
  708.     TQ3Status            myStatus = kQ3Failure;
  709.     ApplicationDataHdl    myAppData;
  710.     TQ3ViewObject        myView;
  711.     TQ3Vector3D            myTranslate;
  712.     
  713.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  714.     if (myAppData == NULL)
  715.         return(myStatus);
  716.         
  717.     HLock((Handle) myAppData);
  718.     
  719.     myTranslate = *(TQ3Vector3D *) &(*myAppData)->fGroupCenter;
  720.     
  721.     myView = (**myAppData).fView;
  722.     
  723.     // our rendering loop
  724.     myStatus = Q3View_StartRendering(myView);
  725.     if (myStatus != kQ3Failure)
  726.         do {
  727.             Q3Style_Submit((**myAppData).fInterpolation, myView);
  728.             Q3Style_Submit((**myAppData).fBackFacing, myView);
  729.             Q3Style_Submit((**myAppData).fFillStyle, myView);
  730.                 
  731.             Q3MatrixTransform_Submit(&(**myAppData).fRotation, myView);
  732.                 
  733.             Q3TranslateTransform_Submit(&myTranslate, myView);
  734.             Q3DisplayGroup_Submit((**myAppData).fModel, myView);
  735.         
  736.         } while (Q3View_EndRendering(myView) == kQ3ViewStatusRetraverse);
  737.     
  738.     HUnlock((Handle) myAppData);
  739.  
  740.     return(myStatus);
  741. }
  742.  
  743.  
  744. //////////
  745. //
  746. // VR3DObjects_GetModelFromFile
  747. // Open a model contained in a 3DMF file.
  748. //
  749. //////////
  750.  
  751. void VR3DObjects_GetModelFromFile (void)
  752. {
  753.     ApplicationDataHdl    myAppData;
  754.     TQ3ViewObject        myView;
  755.     OSErr                myErr = noErr;
  756.     SFTypeList            myTypeList = {'3DMF'};
  757.     StandardFileReply    myReply;
  758.     short                myRefNum;
  759.     QTVRInstance        myInstance;
  760.     
  761.     myAppData = (ApplicationDataHdl)GetAppDataFromFrontWindow();
  762.     if (myAppData == NULL)
  763.         return;
  764.         
  765.     myView = (**myAppData).fView;
  766.  
  767.     StandardGetFilePreview(0L, 1, myTypeList, &myReply);
  768.     if (myReply.sfGood) {
  769.     
  770.         // this might take a while, so display the watch cursor    
  771.         SetCursor(*GetCursor(watchCursor));
  772.  
  773.         myErr = FSpOpenDF(&myReply.sfFile, fsRdPerm, &myRefNum);
  774.         if (myErr == noErr) {
  775.             
  776.             TQ3StorageObject    myStorage;
  777.             TQ3FileObject        myFile;
  778.             TQ3Status            myStatus;
  779.             TQ3Object             myModel;
  780.             TQ3Object            myObject = NULL;
  781.             TQ3Boolean            isEOF;
  782.             TQ3GroupObject         myLightGroup = NULL;
  783.             
  784.             // create storage and file objects
  785.             myStorage = Q3MacintoshStorage_New(myRefNum);
  786.             if (myStorage == NULL)
  787.                 return;
  788.             myFile = Q3File_New();
  789.             if (myFile == NULL)
  790.                 return;
  791.             
  792.             // associate the storage with the file
  793.             Q3File_SetStorage(myFile, myStorage);
  794.             Q3Object_Dispose(myStorage);
  795.         
  796.             // read the drawable objects from the file object into a new group
  797.             myModel = Q3DisplayGroup_New();
  798.             if (myModel != NULL) {
  799.                 myStatus = Q3File_OpenRead(myFile, NULL);
  800.                 if (myStatus == kQ3Success) {
  801.                 
  802.                     do {
  803.                         myObject = Q3File_ReadObject(myFile);
  804.                         
  805.                         // if object read is not NULL then process object
  806.                         if (myObject != NULL) {
  807.                             if (Q3Object_IsDrawable(myObject))
  808.                                 Q3Group_AddObject(myModel, myObject);
  809.                             
  810.                             //if (Q3Object_IsType(myObject, kQ3SharedTypeViewHints))
  811.                             //    if (myView)
  812.                             //        Q3ViewHints_GetLightGroup((TQ3ViewHintsObject)myObject, &myLightGroup);
  813.                             
  814.                             Q3Object_Dispose(myObject);
  815.                         }
  816.                         
  817.                         isEOF = Q3File_IsEndOfFile(myFile);
  818.                     } while (isEOF == kQ3False);
  819.                     
  820.                     if (myLightGroup) {
  821.                         Q3View_SetLightGroup(myView, myLightGroup);
  822.                         Q3Object_Dispose(myLightGroup);
  823.                     }
  824.                     else {
  825.                         myLightGroup = VR3DObjects_CreateLights();
  826.                         Q3View_SetLightGroup(myView, myLightGroup);
  827.                         Q3Object_Dispose(myLightGroup);
  828.                     }
  829.                 }
  830.  
  831.                 // install new model in application data structure
  832.                 (**myAppData).fModel = myModel;
  833.                 
  834.                 // reset the rotation matrix to the identity matrix
  835.                 Q3Matrix4x4_SetIdentity(&(**myAppData).fRotation);
  836.                 
  837.                 // reset other model parameters
  838.                 Q3Point3D_Set(&(**myAppData).fGroupCenter, 0.0, 0.0, 0.0);
  839.                 (**myAppData).fGroupScale = 1.0;
  840.                 (**myAppData).fTexture = NULL;
  841.                 (**myAppData).fTextureIsMovie = false;
  842.                 (**myAppData).fObjectIndex = i3DMFFile;        // not a predefined object
  843.             }
  844.             
  845.             // close the file object
  846.             Q3File_Close(myFile);
  847.             
  848.             // close the file, since we've got the data we need
  849.             FSClose(myRefNum);
  850.             
  851.             // redraw the screen (to display new model)
  852.             (**myAppData).fMustRender = true;
  853.             myInstance = GetQTVRInstanceFromFrontWindow();
  854.             QTVRUpdate(myInstance, kQTVRCurrentMode);
  855.         }
  856.     } else {
  857.         // if the user didn't select a file, we force a box
  858.         (**myAppData).fModel = VR3DObjects_CreateModel(kQ3GeometryTypeBox);
  859.     }
  860.     
  861.     // restore original cursor
  862.     SetCursor(&qd.arrow);
  863. }
  864.  
  865.  
  866. //////////
  867. //
  868. // VR3DObjects_InstallPrescreenRoutine
  869. // Install a prescreen buffer imaging complete procedure
  870. // to copy the rendered 3D image into the prescreen buffer (whence QTVR puts it on the screen).
  871. //
  872. //////////
  873.  
  874. void VR3DObjects_InstallPrescreenRoutine (QTVRInstance theInstance, WindowObject theWindowObject)
  875. {
  876.     ImagingCompleteUPP    myImagingProc;
  877.  
  878.     myImagingProc = NewImagingCompleteProc(VR3DObjects_PrescreenRoutine);    
  879.     QTVRSetPrescreenImagingCompleteProc(theInstance, myImagingProc, (SInt32)theWindowObject, 0);
  880.  
  881.     // we want our prescreen imaging procedure to be called *every* time a QTVR image is drawn,
  882.     // so we must turn off direct screen drawing for all drawing modes (both motion and static)
  883.     QTVRSetImagingProperty(theInstance, kQTVRAllModes, kQTVRImagingDirectDraw, 0);
  884. }
  885.  
  886.  
  887. ///////////
  888. //
  889. // VR3DObjects_InstallInterceptRoutine
  890. // Install a QTVR intercept procedure to signal that the camera needs to be updated.
  891. //
  892. //////////
  893.  
  894. void VR3DObjects_InstallInterceptRoutine (QTVRInstance theInstance, WindowObject theWindowObject)
  895. {
  896.     QTVRInterceptUPP    myInterceptProc;
  897.     
  898.     myInterceptProc = NewQTVRInterceptProc(VR3DObjects_InterceptRoutine);    
  899.     
  900.     // we'll just use the same intercept proc for each intercepted procedure
  901.     QTVRInstallInterceptProc(theInstance, kQTVRSetPanAngleSelector, myInterceptProc, (SInt32)theWindowObject, 0);
  902.     QTVRInstallInterceptProc(theInstance, kQTVRSetTiltAngleSelector, myInterceptProc, (SInt32)theWindowObject, 0);
  903.     QTVRInstallInterceptProc(theInstance, kQTVRSetFieldOfViewSelector, myInterceptProc, (SInt32)theWindowObject, 0);
  904. }
  905.  
  906.  
  907. ///////////
  908. //
  909. // VR3DObjects_PrescreenRoutine
  910. // Draw the rendered 3D scene into the current graphics world.
  911. //
  912. //////////
  913.  
  914. pascal OSErr VR3DObjects_PrescreenRoutine (QTVRInstance theInstance, WindowObject theWindowObject)
  915. {
  916. #pragma unused(theInstance)
  917.  
  918.     ApplicationDataHdl    myAppData;
  919.     CGrafPtr            myGWorld;
  920.     GDHandle            myGDevice;
  921.         
  922.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  923.     if (myAppData == NULL)
  924.         return(paramErr);
  925.  
  926.     HLock((Handle)myAppData);
  927.  
  928.     // if there is an active movie texture, advance the movie to the next frame
  929.     if ((**myAppData).fTexture) {
  930.         if ((**myAppData).fTextureIsMovie)
  931.             VR3DTexture_NextFrame((**myAppData).fTexture);
  932.         (**myAppData).fMustRender = true;
  933.     }
  934.     
  935.     // if animation is active, animate the model
  936.     if ((**myAppData).fObjectIsAnimated) {
  937.         VR3DObjects_AnimateModel(theWindowObject);
  938.         (**myAppData).fMustRender = true;
  939.     }
  940.  
  941.     // if the camera needs to be updated, do so
  942.     if ((**myAppData).fCameraChanged) {
  943.         VR3DObjects_SetCamera(theWindowObject);
  944.         (**myAppData).fMustRender = true;
  945.     }
  946.  
  947.     // if a new image needs to be rendered, do so and clear the render flag
  948.     if ((**myAppData).fMustRender) {
  949.         VR3DObjects_DrawModel(theWindowObject);
  950.         (**myAppData).fMustRender = false;
  951.     }
  952.     
  953.     // on entry, the current graphics world is set to the prescreen buffer
  954.     GetGWorld(&myGWorld, &myGDevice);
  955.     
  956.     OpColor(&kClearColor);
  957.     RGBBackColor(&kClearColor);
  958.     
  959.     // copy the rendered image to the prescreen buffer
  960.     CopyBits((BitMapPtr) &(**myAppData).fGWorld->portPixMap,
  961.               (BitMapPtr)&(**(myGWorld->portPixMap)).baseAddr,
  962.               &(**myAppData).fGWorld->portRect, 
  963.               &(**(myGWorld->portPixMap)).bounds,
  964.               srcCopy | transparent, 
  965.               0L);
  966.               
  967.     HUnlock((Handle)myAppData);
  968.     
  969.     return(noErr);
  970. }
  971.  
  972.  
  973. //////////
  974. //
  975. // VR3DObjects_InterceptRoutine
  976. // Signal that the camera needs to be updated.
  977. // (We could easily do this elsewhere, but this works for now....)
  978. //
  979. //////////
  980.  
  981. pascal void VR3DObjects_InterceptRoutine (QTVRInstance theInstance, QTVRInterceptPtr theMsg, WindowObject theWindowObject, Boolean *cancel)
  982. {
  983. #pragma unused(theInstance)
  984.  
  985.     Boolean                    myCancelInterceptedProc = false;    // true == do NOT call thru; false == call thru
  986.     ApplicationDataHdl        myAppData;
  987.     
  988.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
  989.     if (myAppData == NULL)
  990.         return;
  991.  
  992.     switch (theMsg->selector) {
  993.     
  994.         case kQTVRSetPanAngleSelector:
  995.         case kQTVRSetTiltAngleSelector:
  996.         case kQTVRSetFieldOfViewSelector:
  997.             (**myAppData).fCameraChanged = true;
  998.             break;            
  999.         default:
  1000.             break;
  1001.     }
  1002.     
  1003.     *cancel = myCancelInterceptedProc;
  1004. }
  1005.  
  1006.  
  1007. //////////
  1008. //
  1009. // VR3DObjects_SetCamera
  1010. // Set the point-of-interest and FOV of the 3D camera associated with the specified window object.
  1011. //
  1012. //////////
  1013.  
  1014. void VR3DObjects_SetCamera (WindowObject theWindowObject)
  1015. {
  1016.     ApplicationDataHdl        myAppData;
  1017.     TQ3ViewObject            myView;
  1018.     TQ3CameraObject            myCamera;
  1019.     TQ3CameraPlacement        myCameraPos;
  1020.     QTVRInstance            myInstance;
  1021.     
  1022.     // get the QTVR instance associated with the specified window
  1023.     if (theWindowObject == NULL)
  1024.         return;
  1025.     
  1026.     myInstance = (**theWindowObject).fInstance;
  1027.     if (myInstance == NULL)
  1028.         return;
  1029.         
  1030.     // get the view object associated with the specified window
  1031.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);    
  1032.     if (myAppData == NULL)
  1033.         return;
  1034.     myView = (**myAppData).fView;
  1035.  
  1036.     // get the camera
  1037.     Q3View_GetCamera(myView, &myCamera);
  1038.     if (myCamera != NULL) {
  1039.         float                myFOV, myPan, myTilt;
  1040.         TQ3Point3D            myPoint;
  1041.         
  1042.         // set the camera's field of view
  1043.         myFOV = QTVRGetFieldOfView(myInstance);
  1044.         if ((**myAppData).fQD3DFOVIsVert) {
  1045.             Q3ViewAngleAspectCamera_SetFOV(myCamera, myFOV);
  1046.         } else {
  1047.             float            myRatio;
  1048.             
  1049.             Q3ViewAngleAspectCamera_GetAspectRatio(myCamera, &myRatio);
  1050.             Q3ViewAngleAspectCamera_SetFOV(myCamera, myFOV * myRatio);
  1051.         }
  1052.  
  1053.         // set the camera's point of interest, based on current pan and tilt angles
  1054.         myPan = QTVRGetPanAngle(myInstance);
  1055.         myTilt = QTVRGetTiltAngle(myInstance);
  1056.  
  1057.         myPoint.x = -sin(myPan) * cos(myTilt) * k3DObjectDistance;
  1058.         myPoint.y = sin(myTilt) * k3DObjectDistance;
  1059.         myPoint.z = -cos(myPan) * cos(myTilt) * k3DObjectDistance;
  1060.         
  1061.         Q3Camera_GetPlacement(myCamera, &myCameraPos);
  1062.         myCameraPos.pointOfInterest = myPoint;
  1063.     
  1064.         // update the QD3D camera
  1065.         Q3Camera_SetPlacement(myCamera, &myCameraPos);
  1066.         Q3View_SetCamera(myView, myCamera);
  1067.         Q3Object_Dispose(myCamera);
  1068.     }
  1069. }
  1070.  
  1071.  
  1072. //////////
  1073. //
  1074. // VR3DObjects_SetCameraAspectRatio
  1075. // Adjust the aspect ratio of the QuickDraw 3D camera based on current window shape.
  1076. //
  1077. //////////
  1078.  
  1079. void VR3DObjects_SetCameraAspectRatio (WindowObject theWindowObject)
  1080. {
  1081.     ApplicationDataHdl                myAppData;
  1082.     TQ3ViewObject                    myView;
  1083.     TQ3CameraObject                    myCamera;
  1084.  
  1085.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);    
  1086.     if (myAppData == NULL)
  1087.         return;
  1088.         
  1089.     // get the window's view and camera objects
  1090.     myView = (**myAppData).fView;
  1091.     Q3View_GetCamera(myView, &myCamera);
  1092.  
  1093.     // adjust the aspect ratio of the camera
  1094.     if (myCamera != NULL) {
  1095.         Rect                        myRect;
  1096.         float                        myRatio;
  1097.     
  1098.         // get the size of the specified window
  1099.         if ((**theWindowObject).fMovie != NULL)
  1100.             GetMovieBox((**theWindowObject).fMovie, &myRect);
  1101.     
  1102.         // calculate the aspect ratio of the movie rectangle
  1103.         myRatio = (float)(myRect.right - myRect.left) / (float)(myRect.bottom - myRect.top);
  1104.  
  1105.         // determine whether QD3D FOV is horizontal or vertical
  1106.         (**myAppData).fQD3DFOVIsVert = (myRatio >= 1.0);
  1107.                 
  1108.         // adjust camera's aspect ratio
  1109.         Q3ViewAngleAspectCamera_SetAspectRatio(myCamera, myRatio);
  1110.         Q3Object_Dispose(myCamera);
  1111.     }
  1112. }
  1113.  
  1114.  
  1115. //////////
  1116. //
  1117. // VR3DObjects_UpdateDrawContext
  1118. // Delete current draw context and create a new one based on current window size.
  1119. //
  1120. //////////
  1121.  
  1122. void VR3DObjects_UpdateDrawContext (WindowObject theWindowObject)
  1123. {
  1124.     ApplicationDataHdl                myAppData;
  1125.     TQ3ViewObject                    myView;
  1126.     TQ3DrawContextObject            myDrawContext;
  1127.     CGrafPtr                        mySavedPort;
  1128.     GDHandle                        mySavedDevice;
  1129.     Rect                            myRect;
  1130.     OSErr                            myErr;
  1131.  
  1132.     myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);    
  1133.     if (myAppData == NULL)
  1134.         return;
  1135.         
  1136.     // lock the application data handle
  1137.     HLock((Handle)myAppData);
  1138.     
  1139.     // get the window's view and draw context objects
  1140.     myView = (**myAppData).fView;
  1141.     Q3View_GetDrawContext(myView, &myDrawContext);
  1142.  
  1143.     // get the size of the specified window
  1144.     if ((**theWindowObject).fMovie != NULL)
  1145.         GetMovieBox((**theWindowObject).fMovie, &myRect);
  1146.     
  1147.     // get the current drawing environment
  1148.     GetGWorld(&mySavedPort, &mySavedDevice);
  1149.  
  1150.     // dispose of the current draw context GWorld
  1151.     DisposeGWorld((**myAppData).fGWorld);
  1152.     
  1153.     // create a new offscreen GWorld that is the size of the window area
  1154.     myErr = NewGWorld(&(**myAppData).fGWorld, 32, &myRect, NULL, NULL, 0L);
  1155.     if (myErr != noErr)
  1156.         return;
  1157.  
  1158.     // erase the draw context buffer to our masking color
  1159.     SetGWorld((**myAppData).fGWorld, NULL);
  1160.     RGBBackColor(&kClearColor);
  1161.     EraseRect(&myRect);
  1162.             
  1163.     // restore the original drawing environment
  1164.     SetGWorld(mySavedPort, mySavedDevice);
  1165.     
  1166.     if (myDrawContext != NULL) {
  1167.         // get rid of existing draw context    
  1168.         Q3Object_Dispose(myDrawContext);        
  1169.     
  1170.         // create and set draw context
  1171.         myDrawContext = VR3DObjects_CreateDrawContext((**myAppData).fGWorld);
  1172.         Q3View_SetDrawContext(myView, myDrawContext);
  1173.         Q3Object_Dispose(myDrawContext);
  1174.     }
  1175.  
  1176.     HUnlock((Handle)myAppData);
  1177. }
  1178.  
  1179.  
  1180. //////////
  1181. //
  1182. // VR3DObjects_GetEmbeddedMovie
  1183. // Get the QuickTime movie to be used as a texture map.
  1184. // Returns a Boolean to indicate success (true) or failure (false).
  1185. //
  1186. //////////
  1187.  
  1188. Boolean VR3DObjects_GetEmbeddedMovie (Movie *theMoviePtr)
  1189. {
  1190.     StandardFileReply        myReply;
  1191.     short                    myNumTypes = 1;
  1192.     SFTypeList                myTypes = {'MooV', 0};
  1193.  
  1194.     // clean up any previous movie
  1195.     if (*theMoviePtr != NULL) {
  1196.         StopMovie(*theMoviePtr);
  1197.         DisposeMovie(*theMoviePtr);
  1198.         *theMoviePtr = NULL;
  1199.     }
  1200.  
  1201.     // elicit the movie file from user
  1202.     StandardGetFilePreview(NULL, myNumTypes, myTypes, &myReply);
  1203.     if (!myReply.sfGood) 
  1204.         return(false);
  1205.         
  1206.     return(VR3DObjects_LoadEmbeddedMovie(&myReply.sfFile, theMoviePtr));
  1207. }
  1208.  
  1209.  
  1210. //////////
  1211. //
  1212. // VR3DObjects_LoadEmbeddedMovie
  1213. // Load the QuickTime movie in the specified file.
  1214. // Returns a Boolean to indicate success (true) or failure (false).
  1215. //
  1216. //////////
  1217.  
  1218. Boolean VR3DObjects_LoadEmbeddedMovie (FSSpec *theMovieFile, Movie *theMoviePtr)
  1219. {
  1220.     OSErr                    myErr = noErr;
  1221.     short                    myMovieFileRef;
  1222.     Rect                    myRect;
  1223.  
  1224.     // open the movie
  1225.     myErr = OpenMovieFile(theMovieFile, &myMovieFileRef, fsRdPerm);
  1226.     if (myErr != noErr)
  1227.         return(false);
  1228.  
  1229.     myErr = NewMovieFromFile(theMoviePtr, myMovieFileRef, NULL, (StringPtr)NULL, newMovieActive, NULL);
  1230.     if (myErr != noErr)
  1231.         return(false);
  1232.  
  1233.     CloseMovieFile(myMovieFileRef);
  1234.         
  1235.     SetMovieMatrix(*theMoviePtr, NULL);
  1236.     
  1237.     SetRect(&myRect, 0, 0, 128, 128);
  1238.     SetMovieBox(*theMoviePtr, &myRect);
  1239.  
  1240.     return(true);
  1241. }
  1242.     
  1243.     
  1244. //////////
  1245. //
  1246. // VR3DObjects_LoopEmbeddedMovie
  1247. // Start the QuickTime movie playing in a loop.
  1248. //
  1249. //////////
  1250.  
  1251. void VR3DObjects_LoopEmbeddedMovie (Movie theMovie, GWorldPtr theGWorld)
  1252. {
  1253.     TimeBase    myTimeBase;
  1254.     
  1255.     SetMovieGWorld(theMovie, theGWorld, nil);
  1256.  
  1257.     // draw the movie first
  1258.     MoviesTask(theMovie, 0);
  1259.     MoviesTask(theMovie, 0);
  1260.  
  1261.     // throw the movie into loop mode
  1262.     myTimeBase = GetMovieTimeBase(theMovie);
  1263.     SetTimeBaseFlags(myTimeBase, GetTimeBaseFlags(myTimeBase) | loopTimeBase);
  1264.  
  1265.     // start playing the movie
  1266.     StartMovie(theMovie);
  1267. }
  1268.         
  1269.  
  1270. //////////
  1271. //
  1272. // VR3DObjects_GetEmbeddedPicture
  1273. // Get the picture to be used as a texture map from a PICT file.
  1274. // (This routine is modeled on IM: Imaging With QuickDraw, pp. 7-13f.)
  1275. //
  1276. //////////
  1277.  
  1278. PicHandle VR3DObjects_GetEmbeddedPicture (void)
  1279. {
  1280.     OSErr                    myErr = noErr;
  1281.     SFTypeList                myTypeList = {'PICT'};
  1282.     StandardFileReply        myReply;
  1283.     short                    myNumTypes = 1;
  1284.     short                    myRefNum;
  1285.     long                    myLength;
  1286.     PicHandle                myPicture = NULL;
  1287.  
  1288.     // elicit the picture file from user
  1289.     StandardGetFilePreview(NULL, myNumTypes, myTypeList, &myReply);
  1290.     if (myReply.sfGood) {
  1291.     
  1292.         // open the picture file and read in picture data
  1293.         myErr = FSpOpenDF(&myReply.sfFile, fsRdPerm, &myRefNum);
  1294.         if (myErr == noErr) {
  1295.             myErr = GetEOF(myRefNum, &myLength);
  1296.             if (myErr != noErr)
  1297.                 return(myPicture);
  1298.                 
  1299.             myErr = SetFPos(myRefNum, fsFromStart, kPicFileHeaderSize);
  1300.             myLength -= kPicFileHeaderSize;
  1301.             myPicture = (PicHandle)NewHandleClear(myLength);
  1302.             if ((myErr == noErr) && (myPicture != NULL)) {
  1303.                 HLock((Handle)myPicture);
  1304.                 myErr = FSRead(myRefNum, &myLength, (Ptr)*myPicture);
  1305.                 HUnlock((Handle)myPicture);
  1306.             }
  1307.             
  1308.             // close the file, since we've got the data we need
  1309.             FSClose(myRefNum);
  1310.         }
  1311.     }
  1312.     
  1313.     return(myPicture);
  1314. }
  1315.  
  1316.  
  1317. //////////
  1318. //
  1319. // VR3DObjects_FadeObjects
  1320. // Fade the 3D model in or out.
  1321. //
  1322. //////////NOT WORKING QUITE YET
  1323.  
  1324. void VR3DObjects_FadeObjects (ApplicationDataHdl theAppData, Boolean isShow)
  1325. {
  1326.     TQ3ViewObject                    myView;
  1327.     TQ3GroupObject                    myGroup;
  1328.     TQ3GroupPosition                myPos;
  1329.     TQ3Object                        myLight;
  1330.     TQ3Status                        myStatus;
  1331.     TQ3ColorRGB                        myColor;
  1332.     float                            myIndex;
  1333.  
  1334.     if (theAppData == NULL)
  1335.         return;
  1336.         
  1337.     // get the view and the 3D model
  1338.     myView = (**theAppData).fView;
  1339.     if (myView == NULL)
  1340.         return;
  1341.     
  1342.     myStatus = Q3View_GetLightGroup(myView, &myGroup);
  1343.     if (myStatus == kQ3Success) {
  1344.         for (Q3Group_GetFirstPosition(myGroup, &myPos); myPos != NULL; Q3Group_GetNextPosition(myGroup, &myPos)) {
  1345.             myStatus = Q3Group_GetPositionObject(myGroup, myPos, &myLight); 
  1346.             if (myStatus != kQ3Success)
  1347.                 break;  
  1348.  
  1349.             if (isShow) {
  1350.                 for (myIndex = 0.0; myIndex < 1.0; myIndex += 0.1) {
  1351.                     Q3ColorRGB_Set(&myColor, myIndex, 1.0, myIndex);
  1352.                     Q3Light_SetColor(myLight, &myColor);
  1353.                     //QTVRUpdate(myInstance, kQTVRCurrentMode);
  1354.                 }
  1355.             } else {
  1356.                 for (myIndex = 1.0; myIndex > 0.0; myIndex -= 0.1) {
  1357.                     Q3ColorRGB_Set(&myColor, myIndex, 1.0, myIndex);
  1358.                     Q3Light_SetColor(myLight, &myColor);
  1359.                     //QTVRUpdate(myInstance, kQTVRCurrentMode);
  1360.                 }
  1361.             }
  1362.             
  1363.             Q3Object_Dispose(myLight);
  1364.         }
  1365.     }
  1366. }